<template>
	<view
	v-if="!stop"
	class="yb-tap yb-flex"
	:id="customIdSync"
	:class="customClassSync"
	ref="ybTap" @tap="onTap"
	@longpress="onLongpress"
	@touchstart="onTouchstart"
	@touchmove="onTouchmove"
	@touchend="onTouchend"
	@touchcancel="onTouchend"
	:style="rootStyle">
		<view class="active yb-flex" :class="activeClass" ref="active" :style="activeStyle" v-if="!disabled"></view>
		<slot></slot>
	</view>
	<view
	v-else
	class="yb-tap yb-flex"
	:id="customIdSync"
	:class="customClassSync"
	ref="ybTap" @tap.stop="onTap"
	@longpress="onLongpress"
	@touchstart="onTouchstart"
	@touchmove="onTouchmove"
	@touchend="onTouchend"
	@touchcancel="onTouchend"
	:style="rootStyle">
		<view class="active yb-flex" :class="activeClass" ref="active" :style="activeStyle" v-if="!disabled"></view>
		<slot></slot>
	</view>
</template>

<script>
	import Util from '../../js_sdk/util.js'
	import ComponentMixin from '../../js_sdk/componentMixin.js'
	// #ifdef APP-NVUE
	const Binding = uni.requireNativePlugin('bindingx')
	// #endif
	export default {
		mixins: [ComponentMixin],
		props: {
			disabled: {
				type: Boolean,
				default: false
			},
			//开启双击
			double: {
				type: Boolean,
				default: false
			},
			//阻止冒泡事件
			stop: {
				type: Boolean,
				default: false
			},
			//点击效果
			active: {
				type: [Boolean,String,Object],
				default: false
			},
			borderRadius: {
				type: [String,Number],
				default: 0
			},
			borderTopLeftRadius: {
				type: [String,Number],
				default: 0
			},
			borderTopRightRadius: {
				type: [String,Number],
				default: 0
			},
			borderBottomLeftRadius: {
				type: [String,Number],
				default: 0
			},
			borderBottomRightRadius: {
				type: [String,Number],
				default: 0
			}
		},
		data () {
			return {
				clickTime: 0,
				width: 0,
				height: 0,
				tap_binding: null,
				ripple: false,
				mask: false,
				opacity: false,
				startX: 0,
				startY: 0,
				offsetTop: 0,
				isTouchmove: false//是否触摸移动
			}
		},
		computed: {
			Util () {
				return Util
			},
			rootStyle () {
				return this.filterStyle({
					'border-radius': Util.pixelunit(this.borderRadius),
					'opacity': this.opacity ? 0.5 : 1
				}) + this.customStyleSync
			},
			activeClass () {
				return this.ripple ? 'yb-active-ripple' : ''
			},
			activeStyle () {
				let size = this.width > this.height ? this.width : this.height
				return this.filterStyle(
					this.activeSync.type == 'mask' ? Object.assign({}, {
						right: 0,
						bottom: 0,
						background: this.activeSync.color,
						opacity: this.mask ? 0.3 : 0
					}, this.borderRadius ? {
						'border-radius': Util.pixelunit(this.borderRadius),
					} : {
						'border-top-left-radius': Util.pixelunit(this.borderTopLeftRadius),
						'border-top-right-radius': Util.pixelunit(this.borderTopRightRadius),
						'border-bottom-left-radius': Util.pixelunit(this.borderBottomLeftRadius),
						'border-bottom-right-radius': Util.pixelunit(this.borderBottomRightRadius)
					}) : this.activeSync.type == 'ripple' ? {
						background: this.activeSync.color,
						// #ifndef APP-NVUE
						'animation-duration': this.activeSync.duration + 'ms',
						'width': size + 'px',
						'height': size + 'px',
						'border-radius': size + 'px',
						'left': this.startX + 'px',
						'top': this.startY + 'px'
						// #endif
					} : {}
				)
			},
			activeSync () {
				return Object.assign({}, {
					show: false,
					type: 'opacity',
					color: 'rgba(0,0,0,.6)',
					duration: 600
				}, Util.typeof(this.active) == 'Object' ? this.active : Util.typeof(this.active) == 'Boolean' ? { show: this.active} : Util.typeof(this.active) == 'String' ? { type: this.active, show: true } : {})
			}
		},
		beforeDestroy() {
			if ( this.timer ) {
				clearTimeout(this.timer)
				this.timer = null
			}
			// #ifdef APP-NVUE
			if ( this.tap_binding ) {
				Binding.unbind({
					token: this.tap_binding.token,
					eventType: 'timing'
				})
				this.tap_binding = null
			}
			// #endif
			// #ifndef APP-NVUE
			this.ripple = false
			this.mask = false
			if ( this.tap_timer ) {
				clearTimeout(this.tap_timer)
				this.tap_timer = null
			}
			// #endif
		},
		methods: {
			//长按事件
			onLongpress (e) {
				if ( this.disabled ) {
					return
				}
				this.$emit('longpress', e)
			},
			onTouchmove (e) {
				this.isTouchmove = true
			},
			onTap (e) {
				// #ifdef APP-NVUE
				if ( this.stop ) {
					e.stopPropagation()
				}
				// #endif
				if ( this.disabled ) {
					return
				}
				if ( this.double ) {
					if ( this.timer ) {
						clearTimeout(this.timer)
						this.timer = null
					}
					if ( this.clickTime == 1 ) {
						this.$emit('doubletap', e)
						this.clickTime = 0
					} else {
						this.clickTime++
						this.timer = setTimeout(() => {
							this.$emit('click', e)
							clearTimeout(this.timer)
							this.timer = null
							this.clickTime = 0
						}, 300)
					}
				} else {
					this.$emit('click', e)
				}
			},
			async onTouchstart (e) {
				if ( this.disabled || !this.activeSync.show ) {
					return
				}
				if ( this.activeSync.type == 'ripple' ) {
					let rect = await Util.getRect('.yb-tap', this.$refs.ybTap, this)
					this.offsetTop = rect.top
					this.width = rect.width
					this.height = rect.height
					// #ifdef APP-NVUE
					if ( !this.tap_binding ) {
						let touch = e.touches[0]
						let active = Util.getEl(this.$refs.active)
						let size = this.width > this.height ? this.width : this.height
						let duration = parseFloat(this.activeSync.duration)
						this.tap_binding = Binding.bind({
							eventType:'timing',
							exitExpression: 't>' + duration,
							props: [{
								element: active,
								property:'transform.scale',
								expression:`linear(t, 0, 1, ${duration})`
							},{
								element: active,
								property:'opacity',
								expression:`t<${duration/2}?linear(t, 0, 1, ${duration/2}):linear(t, 1, -1, ${duration})`
							},{
								element: active,
								property:'transform.translateX',
								expression: `linear(t, 0, ${touch.pageX}-${size/2}, 0.1)`
							},{
								element: active,
								property:'transform.translateY',
								expression: `linear(t, 0, ${touch.pageY}-${size/2}, 0.1)`
							},{
								element: active,
								property:'border-radius',
								expression: `linear(t, 0, ${size}, 0.1)`
							},{
								element: active,
								property:'width',
								expression: `linear(t, 0, ${size}, 0.1)`
							},{
								element: active,
								property:'height',
								expression: `linear(t, 0, ${size}, 0.1)`
							}]
						}, (e) => {
							if ( e.state == 'exit' && e.t >= duration ) {
								if ( this.tap_binding ) {
									this.mask = true
									Binding.unbind({
										token: this.tap_binding.token,
										eventType: 'timing'
									})
									this.tap_binding = null
								}
							}
						});
					}
					// #endif
					// #ifndef APP-NVUE
					if ( !this.ripple ) {
						let touch = e.touches[0]
						this.startX = touch.pageX
						this.startY = touch.clientY - this.offsetTop
						this.ripple = true
						this.tap_timer = setTimeout(() => {
							this.ripple = false
							clearTimeout(this.tap_timer)
							this.tap_timer = null
						}, this.activeSync.duration)
					}
					// #endif
				} else if ( this.activeSync.type == 'mask' ) {
					if ( !this.mask ) {
						this.mask = true
					}
				} else {
					if ( !this.opacity ) {
						this.opacity = true
					}
				}
			},
			onTouchend () {
				if ( this.disabled ) {
					return
				}
				if ( this.isTouchmove ) {
					this.isTouchmove = false
				}
				if ( this.mask ) {
					this.mask = false
				}
				if ( this.opacity ) {
					this.opacity = false
				}
			}
		}
	}
</script>

<style scoped>
	/* #ifndef APP-NVUE */
	@keyframes ripple {
		0% {
			transform: translate(-50%, -50%) scale(0);
			opacity: 0;
		}
		50% {
			transform: translate(-50%, -50%) scale(0.5);
			opacity: 0.5;
		}
		100% {
			transform: translate(-50%, -50%) scale(1);
			opacity: 0;
		}
	}
	/* #endif */
	.yb-tap {
		position: relative;
	}
	.yb-tap .active {
		position: absolute;
		top: 0;
		left: 0;
		opacity: 0;
		/* #ifndef APP-NVUE */
		pointer-events: none;
		/* #endif */
	}
	/* #ifdef MP */
	.yb-tap .content {
		position: relative!important;
		/* #ifdef MP */
		top: initial!important;
		left: initial!important;
		right: initial!important;
		bottom: initial!important;
		background: none!important;
		margin: 0!important;
		/* #endif */
	}
	/* #endif */
	/* #ifdef APP-VUE || H5 */
	.yb-tap > :nth-child(n+2) {
		position: relative;
	}
	/* #endif */
	/* #ifndef APP-NVUE */
	.yb-active-ripple {
		animation-name: ripple;
		animation-fill-mode: none;
		animation-iteration-count: 1;
		animation-timing-function: ease-in-out;
	}
	/* #endif */
</style>